אחרי שלמדנו מהן טראנזקציות, ניכנס לאחורי הקלעים שלהן ונראה איך השינויים מטראנזקציה שמתבצעת על ידי סקריפט אחד יהיו נגישים לסקריפט אחר ובאיזה שלב.
Isolation
Isolation היא הפרדה של שתי טראנזקציות אחת מהשנייה, כך שאם טראנזקציה אחת משנה את הנתונים ועדיין לא עשתה Commit, פעולות אחרות על המסד עדיין יעבדו עם הערכים הישנים.
הפעולה "העברת כסף" מחולקת לשני חלקים: להוריד כסף בשורה אחת, להוסיף כסף בשורה אחרת. אם טראנזקציה ביצעה את הפעולה הראשונה ועוד לא ביצעה את השנייה, אנחנו לא רוצים ששליפה שתתבצע במקביל תראה שינוי כלשהו בחשבון. (למרות שזו דוגמה לא ממש הוגנת, בגלל מגנון נעילת הנתונים.)
נעילת נתונים
כדי למנוע בעיות סנכרון נתונים, שכל אחד חושב שהערך האמיתי הוא אחר – מסדי נתונים פשוט מגבילים גישה לאותם נתונים עד שהטראנזקציה תסתיים. השאילתה המקבילה פשוט תחכה בתור עד שהטראנזקציה תסיים את העברת הכספים או עד שתיכשל ותחזיר הכל לקדמותו.
בטבלאות מסוג InnoDB מתבצעת נעילה ברמת השורה. אם טראנזקציה מבצעת פעולה כלשהי על שורה א', קריאה וכתיבה לשורה זו משאילתות מקבילות תהיה חסומה. גישה לשורות אחרות עדיין תהיה אפשרית ותעבוד כמו שצריך. אבל לפעמים נעדיף התנהגות שונה שמוגדרת באמצעות Isolation Level.
Isolation Level
רמת הבידוד (Isolation Level) מגדירה לטראנזקציה אילו נתונים לחסום ומפני אילו פעולות.
בסטנדרט שפת SQL מוגדרות ארבע רמות נעילה:
Read Uncommited
ברמת נעילה Read Uncommited אין ממש נעילה, ופעולות שמתרחשות במהלך הטראנזקציה ניתנות מיד לקריאה, עוד לפני Commit מכל מקום שהוא, כולל מטראנזקציות מקבילות. מצב כזה גורם לקריאה מזוהמת. אם טראנזקציה אחת שינתה נתונים, השנייה קראה אותם ואז הראשונה ויתרה עם Rollback – קיבלנו קריאה שגויה (מזוהמת).
Read Commited
ברמת Read Commited הנתונים מתאפשרים לקריאה מתוך טראנזקציה מקבילה רק אחרי Commit של הטראנזקציה הנוכחית. בין היתר, הטראנזקציה הנוכחית לא תראה את השינויים לפני שתעשה Commit. אם הטראנזקציה מכניסה שורה לטבלה ואז מנסה לעדכן אותה – נקבל שגיאה, כיוון שגם מבחינת הטראנזקציה הנוכחית השינויים עדיין לא נכנסו לתוקף.
Repeatable Reads
Repeatable Reads היא רמת הבידוד ברירת המחדל של MySQL. ההבדל בינה לבין הקודמת (Read Commited) הוא שהיא עצמה תראה את השינויים שהיא עושה. אם היא תכניס שורה לטבלה ואחר כך תנסה לקרוא אותה – היא תוכל, כיוון שהשינויים שנעשו בטראנזקציה נגישים לטראנזקציה עצמה. קריאה של נתונים מבחוץ תחזיר את הנתונים שהופיעו בטלה לפני תחילת הטראנזקציה.
Serializable
Serializable היא רמת הבידוד הכי גבוהה. מתבצעת בה נעילה מלאה לכתיבה וגם לקריאה. טראנזקציות שרוצות לעבוד על אותם נתונים מחכות שהטראנזקציות הקודמות יסיימו.
הגדרת Isolation Level
נוכל לבחור את Isolation Level הרצוי באמצעות הפקודה Set למשתנה tx_isolation באופן הבא:
SET SESSION tx_isolation='SERIALIZABLE';
את הפקודה הזו יש לבצע לפני תחילת הטראנזקציה, ולא לשכוח להחזירה למצב הקודם אחרי, אם רוצים (אבל עדיף פשוט לשנות את הגדרות המסד בקובץ my.cnf אחת ולתמיד).
תגובות לכתבה:
עוד שאלה קלאסית של רעיון עבודה שמעידה על זה, שאתם יודעים משהו מעבר ל crud
מדריך מעולה!
למה זה שימושי?
למקרה שתחליט לשנות את האינטרציה בין טראנזקציות ולחסום גישה לנתונים מסוימים כאשר מישהו עובד איתם. רוב הסיכויים שהשינויים שלך יהיו בין repeatable reads ל serializable ובחזרה. למרות שבמקרים מסוימים לא אכפת לך מ dirty reads ואתה יכול להעלות את הביצועים מזה ששני טראנזקציות יעבדו במקביל.
תודה על התשובה
מה היא הברירת מחדל?
תנסה לבדוק בדוקומנטציה, אבל מהניסיון שלי, עדיף שלא להסתמך על ברירות מחדל, כי הן עלולות להשתנות בגרסאות מאוחרות יותר.
default = repeatable read
1( תודה רבה אלכס
2( ligh הברירת מחדל הרבה פעמים היא הברירה הכי טובה לממוצע. ואם ישנו אותה נבחן מחדש, הטיעון שישנו אותה הוא די טפשי.
ברמת repeatable בזמן הטרנזקציה מאופשר הכנסה של נתונים לא ע"י הטרנזקציה?
קריאה של נתונים מבחוץ תחזיר את הנתונים שהופיעו בטלה לפני תחילת הטראנזקציה.
במחשבה שניה כתוב במדריך כבר מהי ברירת המחדל.
liorel100, אני לא חושב שזה טיעון טיפשי משום שלא תמיד תוכל לשנות פרויקט שכבר עלה לאוויר. אנשים בדרך כלל לא עוברים על אתרים שהם פיתחו לפני שנתיים לחברה מסוימת. חוץ מזה, זה הרבה יותר קל פשוט להגדיר את מה שאתה רוצה וגמרנו.
1) לא הבנתי האם הדרגה השלישית נועלת שינוי נתונים מבחוץ
2) תלוי מאד, הרי גם הגדרות של הדרגות עשויות להשתנות. ולמה שחברה שלא עבדתי עליה תעדכן את גרסת הMYSQL שלה?
לא הבנתי. די ברור שהגרסה של התוכנה תתעדכן, ואז יכול להיות שברירת המחדל תשתנה. זה מה שאמרתי.
ולמה הכוונה שהגדרות של הגדרות עשויות להשתנות? מובן שתמיד יכולים להיות כל מיני שינויים. (אם כי בד"כ לא יהיו כאלה שיגרמו לכך שגרסאות קודמות לא יוכלו לעשות משהו מסוים, כי אז זה יהיה API Break.) מה שאני אומר זה לנסות למנוע בעיות תאימות עם גרסאות לעתיד.
חוץ מזה, אני חושב שזה מנהג מעולה לא להסתמך על ברירות מחדל, ופשוט לכתוב מה שאתה רוצה שיהיה.
אין טעם להמשיך להתווכח, אז בוא פשוט נסכים שלא להסכים. :-)